package org.drl.tvkit.dao;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.drl.tvkit.KitApplication;
import org.drl.tvkit.util.FormatUtils;
import org.drl.tvkit.util.L;
import org.drl.tvkit.util.StringUtil;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.provider.BaseColumns;
import android.util.Log;


public class ApplicationTable extends AbstractTable {
	public static interface OnTableListener {
		void onDataChage();
	}

	/*
	 * 字段 _ID 索引 DATA_TEXT 应用名称 DATA_ICON 应用图标 DATA_PNAME activity包名 DATA_CNAME
	 * activity类名
	 */
	public static final class Fields implements BaseColumns {
		public static final String TAB_NAME = "ApplicationTable";

		public static final String DATA_TEXT = "_DATA_TEXT";
		public static final String DATA_ICON = "_DATA_ICOM";
		public static final String DATA_PNAME = "_DATA_PNAME";
		public static final String DATA_CNAME = "_DATA_CNAME";

		public static final String COLUMNS[] = { _ID, DATA_TEXT, DATA_ICON,
				DATA_PNAME, DATA_CNAME };
	}

	static int getId(Cursor cursor) {
		return cursor.getInt(cursor.getColumnIndex(Fields._ID));
	}

	static String getText(Cursor cursor) {
		return cursor.getString(cursor.getColumnIndex(Fields.DATA_TEXT));
	}

	static String getIcon(Cursor cursor) {
		return cursor.getString(cursor.getColumnIndex(Fields.DATA_ICON));
	}

	static String getPName(Cursor cursor) {
		return cursor.getString(cursor.getColumnIndex(Fields.DATA_PNAME));
	}

	static String getCName(Cursor cursor) {
		return cursor.getString(cursor.getColumnIndex(Fields.DATA_CNAME));
	}

	public static final class AppInfoProto {
		private int id;
		private String text = "";
		private String icon;
		private String pname;
		private String cname;

		public int getId() {
			return id;
		}

		public void setId(int id) {
			this.id = id;
		}

		public String getText() {
			return text;
		}

		public void setText(String text) {
			this.text = text;
		}

		public String getIcon() {
			return icon;
		}

		public void setIcon(String icon) {
			this.icon = icon;
		}

		public String getPname() {
			return pname;
		}

		public void setPname(String pname) {
			this.pname = pname;
		}

		public String getCname() {
			return cname;
		}

		public void setCname(String cname) {
			this.cname = cname;
		}
	}

	private static ApplicationTable instance;

	public static ApplicationTable getInstance() {
		if (instance == null) {
			instance = new ApplicationTable();
		}
		return instance;
	}

	private List<OnTableListener> OnTableListeners = new ArrayList<ApplicationTable.OnTableListener>();;
	private String mIconFilePath;
	private String TAG = "ApplicationTable";
	public static int appCounts;

	private ApplicationTable() {
		File iconFile = new File(KitApplication.getInstance()
				.getFilesDir() + File.separator + "icons");
		if (!iconFile.exists()) {
			iconFile.mkdir();
		}
		mIconFilePath = iconFile.toString();

	}

	public void updataCounts() {
		Runnable run = new Runnable() {

			@Override
			public void run() {
				try {
					SQLiteDatabase db = DataBaseManager.getInstance()
							.getWritableDatabase();
					updateCount(db);
				} catch (Exception e) {
				}
			}
		};
		KitApplication.getInstance().runBackground(run);
	}

	public void addOnTableListener(OnTableListener add) {
		OnTableListeners.add(add);
	}

	public void removeOnTableListener(OnTableListener del) {
		OnTableListeners.add(del);
	}

	public List<OnTableListener> getOnTableListeners() {
		return java.util.Collections.unmodifiableList(OnTableListeners);
	}

	protected void notifyOnTableListeners() {
		L.e(TAG, "notifyOnTableListeners");
		List<OnTableListener> copy = new ArrayList<ApplicationTable.OnTableListener>(
				getOnTableListeners());
		for (OnTableListener _l : copy) {
			try {
				_l.onDataChage();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	@Override
	public void create(SQLiteDatabase db) {
		L.e(TAG, "--------create-----------");
		String sql;
		sql = "CREATE TABLE " + Fields.TAB_NAME + " (" + Fields._ID
				+ " INTEGER PRIMARY KEY," + Fields.DATA_TEXT + " TEXT,"
				+ Fields.DATA_ICON + " TEXT," + Fields.DATA_PNAME + " TEXT,"
				+ Fields.DATA_CNAME + " TEXT);";
		DataBaseManager.execSQL(db, sql);
		initTableDataAsyn(db);
	}

	public int writeItem(String text, String icon, String pname, String cname) {
		ContentValues cv = new ContentValues();
		cv.put(Fields.DATA_TEXT, text);
		cv.put(Fields.DATA_ICON, icon);
		cv.put(Fields.DATA_PNAME, pname);
		cv.put(Fields.DATA_CNAME, cname);
		SQLiteDatabase db = DataBaseManager.getInstance().getWritableDatabase();
		int $id = hasItem(pname);
		if ($id > -1) {
			int $rid = db.update(getTableName(), cv, Fields._ID + "=?",
					new String[] { String.valueOf($id) });
			return $rid;
		} else {
			long id = db.insert(getTableName(), null, cv);
			isWrite = Boolean.TRUE;
			return (int) id;
		}
	}

	private int hasItem(String pname) {
		SQLiteDatabase db = DataBaseManager.getInstance().getReadableDatabase();
		Cursor c = db.query(getTableName(), getProjection(), Fields.DATA_PNAME
				+ "=?", new String[] {pname}, null, null, null);
		if (hasData(c)) {
			c.moveToFirst();
			int _id = c.getInt(c.getColumnIndex(Fields._ID));
			closeCurosr(c);
			return _id;
		} else {
			closeCurosr(c);
			return -1;
		}
	}

	public List<AppInfoProto> readAllList() {
		List<AppInfoProto> mRm = new ArrayList<AppInfoProto>();
		Cursor c = list();
		AppInfoProto $apv;
		while (c.moveToNext()) {
			int $id = getId(c);
			String $text = getText(c);
			String $icon = getIcon(c);
			String $pname = getPName(c);
			String $cname = getCName(c);
			$apv = new AppInfoProto();
			$apv.setId($id);
			$apv.setText($text);
			$apv.setIcon($icon);
			$apv.setPname($pname);
			$apv.setCname($cname);
			mRm.add($apv);
		}
		closeCurosr(c);
		Map<String, AppInfoProto> map = new HashMap<String, AppInfoProto>();
		if (mRm != null && mRm.size() != 0) {
			for (int i = 0; i < mRm.size(); i++) {
				map.put(mRm.get(i).pname, mRm.get(i));
			}
		}
		L.i(TAG, "-----------------map.size()-----------------" + map.size());
		List<AppInfoProto> $mRm = new ArrayList<AppInfoProto>(map.values());
		mRm.clear();
		mRm.addAll($mRm);
		sortApp(mRm);
		return mRm;
	}

	public List<AppInfoProto> readAllList(int MAX_COUNT, AppInfoProto mfrist) {
		List<AppInfoProto> mRm = new ArrayList<AppInfoProto>();
		Cursor c = list();
		AppInfoProto $apv;
		while (c.moveToNext()) {
			int $id = getId(c);
			String $text = getText(c);
			String $icon = getIcon(c);
			String $pname = getPName(c);
			String $cname = getCName(c);
			$apv = new AppInfoProto();
			$apv.setId($id);
			$apv.setText($text);
			$apv.setIcon($icon);
			$apv.setPname($pname);
			$apv.setCname($cname);
			mRm.add($apv);
		}
		closeCurosr(c);
		Map<String, AppInfoProto> map = new HashMap<String, AppInfoProto>();
		if (mRm != null && mRm.size() != 0) {
			for (int i = 0; i < mRm.size(); i++) {
				map.put(mRm.get(i).pname, mRm.get(i));
			}
		}
		L.i(TAG, "-----------------map.size()-----------------" + map.size());
		List<AppInfoProto> $mRm = new ArrayList<AppInfoProto>(map.values());
		mRm.clear();
		
		List<AppInfoProto> mAppList = new ArrayList<ApplicationTable.AppInfoProto>();
		if ($mRm != null && $mRm.size() != 0) {
			L.i(TAG,"-----------------$mRm.size()-----------------"+ $mRm.size());
			if($mRm.size() > MAX_COUNT){
				mRm.add(mfrist);
				mRm.addAll($mRm);
				sortApp(mRm);
				mAppList  = mRm.subList(0, MAX_COUNT);
			}else{
				mRm.addAll($mRm);
				sortApp(mRm);
				return mRm;
			}
		}
		return mAppList;
	}

	private void sortApp(List<AppInfoProto> mList) {
		L.i(TAG, "-----------------mList-----------------" + mList.size());
		List<AppInfoProto> oneList = new ArrayList<AppInfoProto>();
		List<AppInfoProto> ownList = new ArrayList<AppInfoProto>();
		List<AppInfoProto> otherList = new ArrayList<AppInfoProto>();
		for (AppInfoProto _app : mList) {
			L.i(TAG, "-----------------_app-----------------" + _app);
			if (_app != null) {
				String pName = _app.getPname();
				if (StringUtil.isNotNull(pName)) {
					if (pName.equals("all")) {
						oneList.add(_app);
					} else if (pName.startsWith("com.voole")) {
						ownList.add(_app);
					} else {
						otherList.add(_app);
					}
				}
			}
		}
		mList.clear();
		if (oneList.size() > 0 && oneList != null) {
			mList.addAll(oneList);
		}
		mList.addAll(ownList);
		mList.addAll(otherList);
	}

	@Override
	protected String getTableName() {
		return Fields.TAB_NAME;
	}

	@Override
	protected String[] getProjection() {
		return Fields.COLUMNS;
	}

	public void reUpdateTable() {
		SQLiteDatabase db = DataBaseManager.getInstance().getWritableDatabase();
		initTableDataAsyn(db);
	}

	/**
	 * 异步更新应用表格数据
	 */
	private void initTableDataAsyn(final SQLiteDatabase db) {
		L.e(TAG, "initTableData------>START");
		Runnable run = new Runnable() {
			@Override
			public void run() {
				initList(db);
				updateCount(db);
			}
		};
		L.e(TAG, "initTableData-->EXIT");
		KitApplication.getInstance().runBackground(run);
	}

	public AppInfoProto readAppInfo(String packageName) {
		L.e(TAG, "----------readAppInfo-----");
		final Context mContext = KitApplication.getInstance();
		final PackageManager pm = mContext.getPackageManager();
		Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
		mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		final List<ResolveInfo> resloveInfos = pm.queryIntentActivities(
				mainIntent, 0);
		AppInfoProto $app = new AppInfoProto();
		for (ResolveInfo mResolveInfo : resloveInfos) {
			if (mResolveInfo.activityInfo.packageName.equals(packageName)) {
				String className = mResolveInfo.activityInfo.name;
				String name = (String) mResolveInfo.loadLabel(pm);
				Drawable icon = mResolveInfo.loadIcon(pm);
				$app.setText(name);
				$app.setIcon(saveDrawableIcon(icon, packageName + ".png"));
				$app.setPname(packageName);
				$app.setCname(className);
				break;
			}
		}
		return $app;
	};

	private void initList(final SQLiteDatabase db) {
		L.e(TAG, "initList------>START");
		final Context mContext = KitApplication.getInstance();
		final PackageManager pm = mContext.getPackageManager();
		Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
		mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		final List<ResolveInfo> resloveInfos = pm.queryIntentActivities(
				mainIntent, 0);
		appCounts = resloveInfos.size();
		final List<AppInfoProto> _data = new ArrayList<ApplicationTable.AppInfoProto>();
		AppInfoProto _app;
		for (int i = 0; i < resloveInfos.size(); i++) {
			String text = (String) resloveInfos.get(i).loadLabel(pm);
			Drawable icon = resloveInfos.get(i).loadIcon(pm);
			String pname = resloveInfos.get(i).activityInfo.packageName;
			String cname = resloveInfos.get(i).activityInfo.name;
			String iconPath = saveDrawableIcon(icon, "appicon_" + i + ".png");
			Log.i(TAG, "text =" + text + ",iconPath=" + iconPath + ",pname="
					+ pname + ",cname=" + cname);
			_app = new AppInfoProto();
			_app.setText(text);
			_app.setIcon(iconPath);
			_app.setPname(pname);
			_app.setCname(cname);
			_data.add(_app);
		}
		if (_data.size() > 0) {
			for (AppInfoProto _info : _data) {
				if(StringUtil.isNotNull(_info.getText()) & StringUtil.isNotNull(_info.getIcon())
						& StringUtil.isNotNull(_info.getPname()) & StringUtil.isNotNull(_info.getCname())){
					writeItem(_info.getText(), _info.getIcon(), _info.getPname(), _info.getCname());
				}
			}
			if(isWrite){
				notifyOnTableListeners();
			}
		} else {
			L.e(TAG, "数据插入失败");
		}
	}
	private boolean isWrite = Boolean.FALSE;

	String saveDrawableIcon(Drawable icon, String pkgName) {

		File file = new File(mIconFilePath, pkgName);
		byte[] bytes = FormatUtils.getInstance().Drawable2Bytes(icon);
		try {
			FileOutputStream fio = new FileOutputStream(file);
			if (bytes.length > -1) {
				fio.write(bytes);
				fio.flush();
				fio.close();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return file.toString();
	}

	public void insertItem(final String packageName) {
		L.e(TAG, "----------insertItem-----");
		AppInfoProto _item = readAppInfo(packageName);
		SQLiteDatabase db = DataBaseManager.getInstance().getWritableDatabase();
		ContentValues cv = new ContentValues();
		String text = _item.getText();
		String icon = _item.getIcon();
		String pname = _item.getPname();
		String cname = _item.getCname();
		if (StringUtil.isNotNull(text) & StringUtil.isNotNull(icon)
				& StringUtil.isNotNull(pname) & StringUtil.isNotNull(cname)) {
			cv.put(Fields.DATA_TEXT, text);
			cv.put(Fields.DATA_ICON, icon);
			cv.put(Fields.DATA_PNAME, pname);
			cv.put(Fields.DATA_CNAME, cname);
			db.insert(getTableName(), null, cv);
			updateCount(db);
			notifyOnTableListeners();
		}
	}

	public void deleteItem(final String pname) {
		if (pname.equals("com.voole.desktop3")) {
			return;
		}
		L.e(TAG, "----------deleteItem-----");
		final SQLiteDatabase db = DataBaseManager.getInstance()
				.getWritableDatabase();
		File _delFile = null;
		Cursor result = db.query(getTableName(), getProjection(),
				Fields.DATA_PNAME + "= ?", new String[] { pname }, null, null,
				null);
		if (result.moveToNext()) {
			String path = getIcon(result);
			if (StringUtil.isNotNull(path)) {
				_delFile = new File(path);
			}
		}
		closeCurosr(result);
		db.delete(getTableName(), Fields.DATA_PNAME + "= ?",
				new String[] { pname });
		updateCount(db);
		notifyOnTableListeners();
		final File _file = _delFile;
		Runnable run = new Runnable() {
			@Override
			public void run() {
				if (_file != null) {
					if (_file.exists()) {
						_file.delete();
					}
				}
			}
		};
		KitApplication.getInstance().runBackground(run);
	}


	public void updateList(String pname) {
		if (pname.equals("com.voole.desktop3")) {
			return;
		}
		L.e(TAG, "----------updateList-----");
		final SQLiteDatabase db = DataBaseManager.getInstance()
				.getWritableDatabase();
		Cursor result = db.query(getTableName(), getProjection(),
				Fields.DATA_PNAME + "= ?", new String[] { pname }, null, null,
				null);
		if (result.moveToNext()) {
			deleteItem(pname);
		} else {
			insertItem(pname);
		}
		closeCurosr(result);
	}

	void updateCount(SQLiteDatabase db) {
		L.e(TAG, "----------updateCount-----");
		Cursor c = db.query(getTableName(), getProjection(), null, null, null,
				null, null);
		if (hasData(c)) {
			c.getCount();
		}
		closeCurosr(c);
	}
}
